package tools

import (
	"errors"
	"github.com/go-co-op/gocron/v2"
	"github.com/google/uuid"
	"sync"
	"time"
)

var once sync.Once
var DefaultScheduler *TaskScheduler

type TaskScheduler struct {
	Scheduler gocron.Scheduler
}

// https://pkg.go.dev/github.com/go-co-op/gocron/v2#section-readme
// GetDefaultScheduler 得到共有的调度器
func GetDefaultScheduler() *TaskScheduler {
	once.Do(func() {
		scheduler, err := gocron.NewScheduler(
			gocron.WithLocation(time.Local))
		if err != nil {
			panic(err)
		}
		s := &TaskScheduler{
			Scheduler: scheduler,
		}
		scheduler.Start()
		DefaultScheduler = s
	})
	return DefaultScheduler
}

// GetPrivateScheduler 得到私有的调度器
func GetPrivateScheduler() *TaskScheduler {
	scheduler, err := gocron.NewScheduler(
		gocron.WithLocation(time.Local))
	if err != nil {
		panic(err)
	}
	return &TaskScheduler{
		Scheduler: scheduler,
	}
	//scheduler.Start()
}

func (t *TaskScheduler) Start() {
	t.Scheduler.Start()
}

func (t *TaskScheduler) Stop() error {
	err := t.Scheduler.StopJobs()
	if err != nil {
		return err
	}
	return t.Scheduler.Shutdown()

}

func (t *TaskScheduler) RemoveJob(jobID uuid.UUID) error {
	err := t.Scheduler.RemoveJob(jobID)
	if err != nil {
		return err
	}
	return nil
}

// AddOneTimeTask 添加单词立即执行任务
func (t *TaskScheduler) AddOneTimeTask(job func()) (uuid.UUID, error) {
	j, err := t.Scheduler.NewJob(
		gocron.OneTimeJob(
			gocron.OneTimeJobStartImmediately(),
		),
		gocron.NewTask(job),
	)
	if err != nil {
		return uuid.UUID{}, err
	}
	return j.ID(), nil
}

// AddOneTimeDelayTask 添加单次延迟任务在when时间后执行
func (t *TaskScheduler) AddOneTimeDelayTask(when time.Time, job func()) (uuid.UUID, error) {
	j, err := t.Scheduler.NewJob(
		gocron.OneTimeJob(
			gocron.OneTimeJobStartDateTime(when),
		),
		gocron.NewTask(job),
	)
	if err != nil {
		return uuid.UUID{}, err
	}
	return j.ID(), nil
}

// AddCronTask 添加定时任务，根据cron执行 cron五位分别为 分（0-59） 时（0-23） 日（1-31） 月（1-12） 周（0-6）0为周日
// https://www.runoob.com/linux/linux-comm-crontab.html
func (t *TaskScheduler) AddCronTask(cron string, job func()) (uuid.UUID, error) {
	j, err := t.Scheduler.NewJob(
		gocron.CronJob(cron, false),
		gocron.NewTask(job),
	)
	if err != nil {
		return uuid.UUID{}, err
	}
	return j.ID(), nil
}

// AddDailyTask 添加每日任务 intervalDay 间隔天数 times 每日执行时间(可以多个) 例如：[]gocron.AtTime{gocron.NewAtTime(10, 0, 0), gocron.NewAtTime(14, 0, 0)} func NewAtTime(hours, minutes, seconds uint) AtTime
func (t *TaskScheduler) AddDailyTask(intervalDay uint, job func(), times []gocron.AtTime) (uuid.UUID, error) {
	var atTimes gocron.AtTimes
	if len(times) == 0 {
		return uuid.UUID{}, errors.New("每日执行时间未设置")
	} else if len(times) == 1 {
		atTimes = gocron.NewAtTimes(times[0])
	} else {
		atTimes = gocron.NewAtTimes(times[0], times[1:]...)
	}
	j, err := t.Scheduler.NewJob(
		gocron.DailyJob(
			intervalDay,
			atTimes,
		),
		gocron.NewTask(job),
	)
	if err != nil {
		return uuid.UUID{}, err
	}
	return j.ID(), nil
}

// AddWeeklyTask 添加每周任务 intervalWeek 间隔周数 weekday 周几（多个） 例如：time.Friday,time.Monday  times 每日执行时间(可以多个) 例如：[]gocron.AtTime{gocron.NewAtTime(10, 0, 0), gocron.NewAtTime(14, 0, 0)} func NewAtTime(hours, minutes, seconds uint) AtTime
func (t *TaskScheduler) AddWeeklyTask(intervalWeek uint, weekday []time.Weekday, job func(), times []gocron.AtTime) (uuid.UUID, error) {
	var atTimes gocron.AtTimes
	if len(times) == 0 {
		return uuid.UUID{}, errors.New("每日执行时间未设置")
	} else if len(times) == 1 {
		atTimes = gocron.NewAtTimes(times[0])
	} else {
		atTimes = gocron.NewAtTimes(times[0], times[1:]...)
	}
	var weekDays gocron.Weekdays
	if len(weekday) == 0 {
		return uuid.UUID{}, errors.New("每周执行时间未设置")
	} else if len(weekday) == 1 {
		weekDays = gocron.NewWeekdays(weekday[0])
	} else {
		weekDays = gocron.NewWeekdays(weekday[0], weekday[1:]...)
	}
	j, err := t.Scheduler.NewJob(
		gocron.WeeklyJob(
			intervalWeek,
			weekDays,
			atTimes,
		),
		gocron.NewTask(job),
	)
	if err != nil {
		return uuid.UUID{}, err
	}
	return j.ID(), nil
}

// AddMonthlyTask 添加每月任务 intervalMonth 间隔月数 daysOfMonth 每月几号（多个） 例如：1,2,3 times 每日执行时间(可以多个) 例如：[]gocron.AtTime{gocron.NewAtTime(10, 0, 0), gocron.NewAtTime(14, 0, 0)} func NewAtTime(hours, minutes, seconds uint) AtTime
func (t *TaskScheduler) AddMonthlyTask(intervalMonth uint, daysOfMonth []int, job func(), times []gocron.AtTime) (uuid.UUID, error) {
	var atTimes gocron.AtTimes
	if len(times) == 0 {
		return uuid.UUID{}, errors.New("每日执行时间未设置")
	} else if len(times) == 1 {
		atTimes = gocron.NewAtTimes(times[0])
	} else {
		atTimes = gocron.NewAtTimes(times[0], times[1:]...)
	}
	var days gocron.DaysOfTheMonth
	if len(daysOfMonth) == 0 {
		return uuid.UUID{}, errors.New("每月执行时间未设置")
	} else if len(daysOfMonth) == 1 {
		days = gocron.NewDaysOfTheMonth(daysOfMonth[0])
	} else {
		days = gocron.NewDaysOfTheMonth(daysOfMonth[0], daysOfMonth[1:]...)
	}
	j, err := t.Scheduler.NewJob(
		gocron.MonthlyJob(
			intervalMonth,
			days,
			atTimes,
		),
		gocron.NewTask(job),
	)
	if err != nil {
		return uuid.UUID{}, err
	}
	return j.ID(), nil
}
